package com.cskaoyan.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.cskaoyan.mall.commons.exception.ExceptionProcessorUtils;
import com.cskaoyan.mall.commons.exception.ValidateException;
import com.cskaoyan.mall.commons.util.CookieUtil;
import com.cskaoyan.mall.commons.util.jwt.JwtTokenUtils;
import com.cskaoyan.user.constants.UserRetCode;
import com.cskaoyan.user.dal.entitys.Member;
import com.cskaoyan.user.dal.entitys.UserVerify;
import com.cskaoyan.user.dal.persistence.MemberMapper;
import com.cskaoyan.user.dal.persistence.UserVerifyMapper;
import com.cskaoyan.user.model.request.UserLoginRequest;
import com.cskaoyan.user.model.request.UserRegisterRequest;
import com.cskaoyan.user.model.request.UserVerifyRequest;
import com.cskaoyan.user.model.response.CheckLoginResponse;
import com.cskaoyan.user.model.response.UserLoginResponse;
import com.cskaoyan.user.model.response.UserRegisterResponse;
import com.cskaoyan.user.model.response.UserVerifyResponse;
import com.cskaoyan.user.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.UUID;


/**
 * @program: duolaimall
 * @description: 用户注册
 * @author: Lexis
 * @create: 2022-05-18 22:23
 **/
@Slf4j
@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    MemberMapper memberMapper;

    @Autowired
    UserVerifyMapper userVerifyMapper;

    @Autowired
    JavaMailSender mailSender;

    @Value("${email.text}")
    String text;

    @Value("${email.subject}")
    String subject;

    @Value("${spring.mail.username}")
    String from;


    @Transactional
    @Override
    /**
     * @author: lixiaosheng
     * @description: 用户注册
     * @date: 2022/5/18 22:24
     */
    public UserRegisterResponse register(UserRegisterRequest registerRequest) {
        UserRegisterResponse registerResponse = new UserRegisterResponse();
        try {
            // 判空验证
            registerRequest.requestCheck();
            // 验证用户名是否重复
            validateUsernameRepeated(registerRequest.getUserName());
            // 向用户表插入一条数据
            Member member = new Member();
            member.setUsername(registerRequest.getUserName());
            member.setEmail(registerRequest.getEmail());
            // userPwd加密处理，使用md5算法，登录的时候需要同样的解密算法
            String password = DigestUtils.md5DigestAsHex(registerRequest.getUserPwd().getBytes());
            member.setPassword(password);
            member.setCreated(new Date());
            member.setUpdated(new Date());
            member.setIsVerified("N");
            member.setState(1);
            int affectedRows = memberMapper.insert(member);
            // 注册失败
            if (affectedRows != 1) {
                registerResponse.setCode(UserRetCode.USER_REGISTER_FAILED.getCode());
                registerResponse.setMsg(UserRetCode.USER_REGISTER_FAILED.getMessage());
                return registerResponse;
            }

            // 向用户验证表插入一条数据
            UserVerify userVerify = new UserVerify();
            userVerify.setUsername(registerRequest.getUserName());
            // 设置uuid，保证唯一，通过uuid找到该用户的激活记录，从而找到username
            // 使用md5算法
            String key = registerRequest.getUserName() + registerRequest.getUserPwd() + UUID.randomUUID();
            String uuid = DigestUtils.md5DigestAsHex(key.getBytes());
            userVerify.setUuid(uuid);
            userVerify.setRegisterDate(new Date());
            userVerify.setIsVerify("N");
            userVerify.setIsExpire("N");
            int rows = userVerifyMapper.insert(userVerify);
            // 注册失败
            if (rows != 1) {
                registerResponse.setCode(UserRetCode.USER_REGISTER_VERIFY_FAILED.getCode());
                registerResponse.setMsg(UserRetCode.USER_REGISTER_VERIFY_FAILED.getMessage());
                return registerResponse;
            }

            // 发送激活邮件
            sendEmail(uuid, registerRequest);


            // 返回之前打印日志
            log.info("用户注册成功，注册参数request:{}", JSON.toJSONString(registerRequest));

            registerResponse.setCode(UserRetCode.SUCCESS.getCode());
            registerResponse.setMsg(UserRetCode.SUCCESS.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            ExceptionProcessorUtils.wrapperHandlerException(registerResponse, e);
        }
        return registerResponse;
    }

    /**
     * @author: lixiaosheng
     * @description: 发送用户激活邮件
     * @date: 2022/5/19 9:50
     */
    private void sendEmail(String uuid, UserRegisterRequest registerRequest) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setSubject(subject);
        message.setFrom(from);
        message.setTo(registerRequest.getEmail());
        text = String.format(text, registerRequest.getUserName(), uuid);
        message.setText(text);
        mailSender.send(message);
    }

    /**
     * @author: lixiaosheng
     * @description: 验证用户名是否重复
     * @date: 2022/5/18 22:33
     */
    private void validateUsernameRepeated(String userName) {
        Example example = new Example(Member.class);
        example.createCriteria().andEqualTo("username", userName);

        List<Member> members = memberMapper.selectByExample(example);
        if (!CollectionUtils.isEmpty(members)) {
            throw new ValidateException(UserRetCode.USERNAME_ALREADY_EXISTS.getCode(), UserRetCode.USERNAME_ALREADY_EXISTS.getMessage());
        }
    }


    @Transactional
    @Override
    /**
     * @author: lixiaosheng
     * @description: 用户注册激活
     * @date: 2022/5/19 10:44
     */
    public UserVerifyResponse verify(UserVerifyRequest verifyRequest) {
        UserVerifyResponse verifyResponse = new UserVerifyResponse();

        try {
            verifyRequest.requestCheck();

            // 判断用户名和uuid是否匹配
            UserVerify userVerify = new UserVerify();
            userVerify.setUsername(verifyRequest.getUserName());
            userVerify.setUuid(verifyRequest.getUuid());
            List<UserVerify> users = userVerifyMapper.select(userVerify);
            if (CollectionUtils.isEmpty(users)) {
                throw new ValidateException(UserRetCode.USERVERIFY_INFOR_INVALID.getCode(), UserRetCode.USERVERIFY_INFOR_INVALID.getMessage());
            }

            // 修改校验状态
            userVerify.setIsVerify("Y");
            userVerify.setRegisterDate(new Date());
            Example example = new Example(UserVerify.class);
            example.createCriteria()
                    .andEqualTo("username", verifyRequest.getUserName())
                    .andEqualTo("uuid", verifyRequest.getUuid());
            int updateVerify = userVerifyMapper.updateByExampleSelective(userVerify, example);
            if (updateVerify != 1) {
                throw new ValidateException(UserRetCode.USERVERIFY_INFOR_INVALID.getCode(), UserRetCode.USERVERIFY_INFOR_INVALID.getMessage());
            }
            Member member = new Member();
            member.setUpdated(new Date());
            member.setIsVerified("Y");
            Example memberExample = new Example(Member.class);
            memberExample.createCriteria().andEqualTo("username", verifyRequest.getUserName());
            int updateMember = memberMapper.updateByExampleSelective(member, memberExample);
            if (updateMember != 1) {
                throw new ValidateException(UserRetCode.USERVERIFY_INFOR_INVALID.getCode(), UserRetCode.USERVERIFY_INFOR_INVALID.getMessage());
            }

            log.info("用户注册激活成功，注册参数request:{}", JSON.toJSONString(verifyRequest));

            verifyResponse.setCode(UserRetCode.SUCCESS.getCode());
            verifyResponse.setMsg(UserRetCode.SUCCESS.getMessage());
        } catch (ValidateException e) {
            e.printStackTrace();
            ExceptionProcessorUtils.wrapperHandlerException(verifyResponse, e);
        }
        return verifyResponse;
    }

    @Transactional
    @Override
    /**
     * @author: lixiaosheng
     * @description: 登录，成功时将token放入cookie
     * @date: 2022/5/19 11:39
     */
    public UserLoginResponse login(UserLoginRequest loginRequest, HttpServletResponse response) {
        UserLoginResponse loginResponse = new UserLoginResponse();

        try {
            loginRequest.requestCheck();
            Member member = new Member();
            member.setUsername(loginRequest.getUserName());

            member.setPassword(DigestUtils.md5DigestAsHex(loginRequest.getPassword().getBytes()));
            List<Member> user = memberMapper.select(member);
            Member loginMember = null;

            if (CollectionUtils.isEmpty(user)) {
                throw new ValidateException(UserRetCode.USERORPASSWORD_ERRROR.getCode(), UserRetCode.USERORPASSWORD_ERRROR.getMessage());
            }

            loginMember = user.get(0);
            // 判断是否激活
            if ("N".equals(loginMember.getIsVerified())) {
                throw new ValidateException(UserRetCode.USER_ISVERFIED_ERROR.getCode(), UserRetCode.USER_ISVERFIED_ERROR.getMessage());
            }
            loginResponse.setCode(UserRetCode.SUCCESS.getCode());
            loginResponse.setMsg(UserRetCode.SUCCESS.getMessage());
            loginResponse.setUsername(loginMember.getUsername());
            loginResponse.setId(loginMember.getId());
            loginResponse.setPhone(loginMember.getPhone());
            loginResponse.setEmail(loginMember.getEmail());
            loginResponse.setSex(loginMember.getSex());
            loginResponse.setAddress(loginMember.getAddress());
            loginResponse.setFile(loginMember.getFile());
            loginResponse.setDescription(loginMember.getDescription());
            loginResponse.setPoints(loginMember.getPoints());
            loginResponse.setBalance(loginMember.getBalance());
            loginResponse.setState(loginMember.getState());

            // 生成token
            String jsonStr = JSON.toJSONString(loginMember);
            String token = JwtTokenUtils.builder().msg(jsonStr).build().creatJwtToken();
            loginResponse.setToken(token);

            // Cookie cookie = new Cookie("access_token", token);
            Cookie cookie = CookieUtil.genCookie("access_token", token, "/", 7 * 24 * 60 * 60);
            CookieUtil.setCookie(response, cookie);

            log.info("用户登录成功，注册参数request:{}", JSON.toJSONString(loginRequest));
        } catch (ValidateException e) {
            e.printStackTrace();
            ExceptionProcessorUtils.wrapperHandlerException(loginResponse, e);
        }
        return loginResponse;
    }

    @Override
    /**
     * @author: lixiaosheng
     * @description: 通过查看header中是否有数据来验证是否登录过
     * @date: 2022/5/19 12:24
     */
    public CheckLoginResponse checkLogin(HttpServletRequest request) {
        CheckLoginResponse checkLoginResponse = new CheckLoginResponse();
        String token = request.getHeader("user_info");
        if (token == null) {
            return checkLoginResponse;
        }
        Member user = JSON.parseObject(token, Member.class);
        List<Member> members = memberMapper.select(user);
        if (CollectionUtils.isEmpty(members)) {
            return checkLoginResponse;
        }
        checkLoginResponse.setUuid(members.get(0).getId());
        checkLoginResponse.setFile(members.get(0).getFile());
        log.info("用户登录验证成功");
        return checkLoginResponse;
    }
    
}
